#include<iostream>
#include<windows.h>
#include<string>
#include<time.h>
#include<mutex>
#include<thread>
#include<fstream>
#include<future>

using namespace std;
#define LOGAPP logger::getinstance()

enum class loglevel: int{
        Debug = 0,
        Info = 1,
        Error = 2,
        Fatal = 3
    };  //用来标记日志等级

//单例类
class logger {
private:
    loglevel level; //用来标记日志等级
    string content; //文件内容
    string name; //日志文件名称
    static logger* instance;
    static mutex t_mutex;
    logger(){};
public: 
    ~logger()=delete;

    static logger* getinstance(){
        unique_lock<mutex> lock(t_mutex);
        if(instance!=NULL){
            return instance;
        }
        else{
            instance=new logger();
            return instance;
        }
    }
    
    string GetLevelStr(loglevel level);//根据level的值返回对应字符串
    bool CreateLogFile1(string s1,string s2,loglevel level);//创建日志文件
    void CreateLogFile2(string s1,string s2,loglevel level);//异步方式

    string getsname() { return name; }
    void setsname(string sname){this->name=sname;};
    string getcontent() { return content; }
    void setcontent(string scontent) {this->content=scontent;};
    loglevel getLevel(){return level;}
    void setLevel(loglevel level){this->level=level;}

};

logger* logger::instance=NULL;
mutex logger::t_mutex;

string logger::GetLevelStr(loglevel level)
{   
    switch (level)
    {
    case loglevel::Debug:
        return "DEBUG";
    case loglevel::Info:
        return "INFO";
    case loglevel::Error:
        return "ERROR";
    case loglevel::Fatal:
        return "FATAL";
    default:
        return "UNKNOW";
    }
}


//创建日志文件
bool logger::CreateLogFile1(string s1,string s2,loglevel level) {
    ofstream out(s1,ios::app);  //避免覆盖原有内容
    if (out.is_open()) {
        out <<s2<< endl;
        out<<"the level is"<<GetLevelStr(level)<<endl;
        time_t rawtime;
        struct tm * timeinfo;
        timeinfo = localtime ( &rawtime );
        out<<"time:"<<asctime (timeinfo)<<endl;
        //cout<<"open a file"<<endl;
        out.close();
        return true;
    }
    else {
        cout << "no such file" << endl;
        return false;
    }
}

//创建日志文件，使用异步方式
void logger::CreateLogFile2(string s1,string s2,loglevel level){
    future_status status;
    future<void> f1= async([=](){
        ofstream out(s1,ios::app); 
        this_thread::sleep_for(chrono::seconds(3));//模拟耗时
        if (out.is_open()) {
            out <<s2<< endl;
            out<<"the level is "<<GetLevelStr(level)<<endl;
            time_t rawtime;
            struct tm * timeinfo;
            timeinfo = localtime ( &rawtime );
            out<<"time:"<<asctime (timeinfo)<<endl;
            //cout<<"open a file"<<endl;
            out.close();
        }
        else {
            cout << "no such file" << endl;
        }
    });
    do {
        status = f1.wait_for(chrono::seconds(1));
        if (status == future_status::deferred) { // 异步操作尚未完成
            cout << "异步操作尚未完成" << endl;
        }
        else if (status == future_status::timeout) { // 异步操作超时
            cout << "异步操作超时" << endl;
        }
        else if (status == future_status::ready) {
            cout << "异步操作完成" << endl;
        }
    } while (status != future_status::ready);

}

void writelog(){

    string s1=LOGAPP->getsname();
    string s2=LOGAPP->getcontent();
    loglevel level=LOGAPP->getLevel();
    LOGAPP->CreateLogFile2(s1,s2,level);
}


int main() {
     SetConsoleOutputCP(CP_UTF8);
    
    string s1 = "log.txt"; string s2 = "this is a txt1";
    loglevel level=loglevel::Info;
    string s22="this is a test";
    LOGAPP->setsname(s1);
    LOGAPP->setcontent(s2);
    LOGAPP->setLevel(level);

    thread t1(writelog);
    cout<<"创建一个线程t1"<<endl;
    t1.join();

    LOGAPP->setcontent(s22);
    thread t2(writelog);
    cout<<"创建一个线程t2"<<endl;
    t2.join();

    return 0;
}